﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LexicalAnalysisCs;

namespace TextDiffAlgoCs
{
    public class ListComparer : TextComparer
    {
        private static bool[][] GetCompareBoolArray(List<LexicalAnalyzerCs.StrInt> src, List<LexicalAnalyzerCs.StrInt> cmp)
        {
            if (src.Count == 0 || cmp.Count == 0)
            {
                throw new Exception("Must initialize the lists input.");
            }
            bool[][] comps = new bool[cmp.Count][];
            for (int i = 0; i < comps.Length; i++)
            {
                comps[i] = new bool[src.Count];
            }

            for (int i = 0; i < cmp.Count; i++)
            {
                for (int j = 0; j < src.Count; j++)
                {
                    comps[i][j] = cmp[i].mContent.Equals(src[j].mContent);
                }
            }

            return comps;
        }

        public static List<TextDiff> Compare(List<LexicalAnalyzerCs.StrInt> src, List<LexicalAnalyzerCs.StrInt> cmp)
        {
            if (src.Count == 0 || cmp.Count == 0)
            {
                return new List<TextDiff>();
            }
            bool[][] barr = GetCompareBoolArray(src, cmp);
            int[][] miarr = GetStepPathArr(barr);
            int[][] diarr = GetMinStepArr(miarr, barr);
            List<TPoint> pts = new List<TPoint>();
            int maxJ = -1;

            for (int i = 0; i < barr.Length; i++)
            {
                int tmpMaxJ = -1;
                for (int j = 0; j < barr[i].Length; j++)
                {
                    if (j > maxJ && maxJ != -1)
                    {
                        break;
                    }
                    if (barr[i][j])
                    {
                        if (tmpMaxJ == -1)
                        {
                            tmpMaxJ = j;
                        }
                        pts.Add(new TPoint(i, j));
                    }
                }
                if (tmpMaxJ != -1)
                {
                    maxJ = tmpMaxJ;
                }
            }

            int Max = 0;
            int MinStep = -1;
            foreach (TPoint pt in pts)
            {
                if (miarr[pt.x][pt.y] > Max)
                {
                    Max = miarr[pt.x][pt.y];
                }
            }
            foreach (TPoint pt in pts)
            {
                if (MinStep == -1 || (miarr[pt.x][pt.y] >= Max && diarr[pt.x][pt.y] < MinStep))
                {
                    MinStep = diarr[pt.x][pt.y];
                }
            }

            for (int i = 0; i < pts.Count; i++)
            {
                if (miarr[pts[i].x][pts[i].y] < Max || diarr[pts[i].x][pts[i].y] > MinStep)
                {
                    pts.Remove(pts[i]);
                }
            }

            List<TextDiff> diffs = CalcDiffs((pts.Count >= 1 ? pts[0] : null), barr, miarr, diarr);

            return diffs;
        }

        public static List<TextDiff> Compare(List<LexicalAnalyzerCs.StrInt> src, List<LexicalAnalyzerCs.StrInt> cmp, ref double degree1, ref double degree2, ref double degreeMixed)
        {
            if (src.Count == 0 || cmp.Count == 0)
            {
                return new List<TextDiff>();
            }

            int cnt1 = 0, cnt2 = 0;
            List<TextDiff> diffs = Compare(src, cmp);
            foreach (var td in diffs)
            {
                switch (td.getDiffType)
                {
                    case TextDiff.TYPE_DELETE:
                        cnt1 += td.getDiffLength;
                        break;
                    case TextDiff.TYPE_INSERT:
                        cnt2 += td.getDiffLength;
                        break;
                    default:
                        break;
                }
            }

            degree1 = (double)(src.Count - cnt1) / (double)src.Count;
            degree2 = (double)(cmp.Count - cnt2) / (double)cmp.Count;
            degreeMixed = (double)(src.Count + cmp.Count - cnt1 - cnt2) / (double)(src.Count + cmp.Count);

            return diffs;
        }
    }
}
